/*
Generic Doubly Linked List and Persistent Settings project
Author: Mark Newcomb Jr.

*/
#include "FileStorage.h"


FileStorage::~FileStorage()
{
	this->Save();
	filestream.close();
}


bool FileStorage::Save()
{
	return (this->Save(filename));
}


bool FileStorage::Save(std::string fname)
{
	//close the file and reopen it with the fstream::trunc flag set
	//so that all original content will be thrown away
		//VERBOSE
		std::cout<<"\nFILESTORAGE->Save("<<fname<<")\n";
		//V
		
		if(filestream.is_open() == true)
			filestream.close();
		/*
		char* c_fname = (char*)malloc(sizeof(char)+fname.length()+1);
		strcpy(c_fname,fname.c_str());
		*/
	
		filestream.open(fname.c_str(),std::fstream::out|std::fstream::trunc);
		filestream.seekg(0,std::ios::beg);
		filestream.clear();
		filestream.flush();
		
		if(filestream.is_open() != true || filestream.good() != true){
			//VERBOSE
			std::cout<<"\tCould not open file for writing.\n";
			filestream.close();
			return false;
			}
	
	
	Node<std::string> cur_line;
	
		//filestream<<"Settings File\n";
	
	if(p_list->empty(true))
	{
		//VERBOSE
		std::cout<<"\tNothing to write to the file.\n";
		return false;	
	}
	
	while(!p_list->empty(false))
	{
		cur_line = p_list->pop_front();
		//VERBOSE
		std::cout<<"\tWriting cur_line.name("<<cur_line.name<<") and cur_line.data("
		<<cur_line.data<<")\n";
		
			if(cur_line.name != "NULL" && cur_line.data != "NULL")
			{
			filestream<<"'"<<cur_line.name<<"' '"<<cur_line.data<<"'\n";
			std::cout<<"Just wrote something to the file.\n";
			//filestream.flush();
			}
			else
			{
			std::cout<<"\nFILESTORAGE: Nothing to write.\n";
			}
		
	}
	//we've completed without blowing anything up, so we need to take away the trunc flag
	if(filestream.is_open()){
	filestream.close();
	}
	
	filestream.open(fname.c_str(),std::fstream::in|std::fstream::out);
	if(filestream.is_open() != true || filestream.good() != true)
			return false;
	
//delete c_fname;	
return true;
}

bool FileStorage::Load(std::string fname)
{
	//make the filestream object close anything if it's open, then open the file 
	//VERBOSE
	char* c_fname = (char*)malloc(sizeof(char)+fname.length()+1);
		strcpy(c_fname,fname.c_str());
	
	std::cout<<"FILESTORAGE->Load("<<c_fname<<")\n";
	if(filestream.is_open())
		filestream.close();
	
	
		
	filestream.open(c_fname,std::fstream::in);
	if(!filestream.is_open()){
		//VERBOSE
		std::cout<<"FILESTORAGE->Load.  Could not open file.\n";
		return false;
		}
		
	//used as a buffer
	std::string str, *cur_rawline;
	cur_rawline = &str;
	Node<std::string> cur_node;
	
	//make sure our stream object starts at the beginning of the file
	filestream.seekg(0,std::ios::beg);
	
	//read the file line by line, parse the line, and store it in the DLList
	//VERBOSE:
		std::cout<<"FILESTREAM->Load.  Beginning to read file.\n";
	while(!filestream.eof())
	{
		
		getline(filestream,*cur_rawline);
		//VERBOSE
		std::cout<<"\tthis->ParseLine("<<*cur_rawline<<")\n";
		cur_node = this->ParseLine(cur_rawline);
		if(cur_node.name != "NULL" && cur_node.data != "NULL")
			p_list->push_front(cur_node.name,cur_node.data);
		
	};
	
	
	
	if(filestream.is_open())
		filestream.close();
	
	delete c_fname;
	return true;
}
	
//TODO:use boost regular expressions to parse the line
//instead of this god-awful hack.
//right now, this works by finding the first ' mark, the next ' mark, and 
//taking what's in between them.  then it finds the 3rd ' mark and 4th '
//and gets what is in between those.  However, the way i've done it is 
//extremely inelegant, and would look much nicer with regular expressions
//or a nice lightweight string parsing library
Node<std::string> FileStorage::ParseLine(std::string* line)
{
	Node<std::string> retNode;
	std::string name,value;
	int beg_pos=0,fin_pos=0;
	
	for(int i=0;i<line->length();i++)
	{
		if(strcmp((line+i)->c_str(),"'")==0){
			beg_pos=i;
			break;
			}
	}
	for(int i=(beg_pos+1);i < line->length();i++)
	{
		if(strcmp((line+i)->c_str(),"'")==0){
			fin_pos = i;
			break;
			}
	}
	
	if(beg_pos == fin_pos) //we didn't find anything
	{
		retNode.name = "NULL";
		retNode.data = "NULL";
		return retNode;
	}
	else
	{
		for(int i=beg_pos+1;i<fin_pos;i++)
		{
			name+=line->at(i);
		}
		retNode.name = const_cast<char*>(name.c_str());
	}
	
	//now do the same thing, but for the value part of the line
	beg_pos = fin_pos;
	for(int i=fin_pos;i<line->length();i++)
	{
		if(strcmp((line+i)->c_str(),"'")==0){
			beg_pos=i;
			break;
			}
	}
	for(int i=(beg_pos+1);i<line->length();i++)
	{
		if(strcmp((line+i)->c_str(),"'")==0){
			fin_pos = i;
			break;
			}
	}
	if(beg_pos == fin_pos) //we didn't find anything
	{
		retNode.name = "NULL";
		retNode.data = "NULL";
		return retNode;
	}
	else
	{
		for(int i=beg_pos+1;i<fin_pos;i++)
		{
			value+=line->at(i);
		}
		retNode.data = value;
	}
return retNode;
}
	